package com.eobard.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.eobard.constant.SecKillConstant;
import com.eobard.entity.Product;
import com.eobard.enums.SecKillEnum;
import com.eobard.mapper.ProductMapper;
import com.eobard.service.ProductService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.concurrent.TimeUnit;

/**
 * @Author: Eobard Gu
 * @Date: 2025-07-15
 * @Description: TODO
 */
@Service
@Slf4j
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {
    @Autowired
    private RedissonClient redissonClient;

    /**
     * 适用于并发量不高的秒杀
     */
    @Override
    @Transactional
    public SecKillEnum purchase(String userId, Long productId) {
        RLock lock = redissonClient.getLock(SecKillConstant.CONCURRENCY_PRODUCT_SECKILL_LOCK + productId);

        try {
            //尝试等待3秒
            boolean flag = lock.tryLock(3, TimeUnit.SECONDS);
            if (flag) {
                Product product = this.getById(productId);
                if (!ObjectUtils.isEmpty(product) && product.getStock() > 0) {
                    product.setStock(product.getStock() - 1);
                    //TODO:这里还可以优化,可以等到库存为0的时候再去更新DB,因为这里使用到了分布式锁,所以不会出现超卖的问题
                    this.updateById(product);
                    log.info("user:{} seckill product:{},last:{}", userId, productId, product.getStock());
                } else {
                    //说明是空的商品或者没有库存了
                    log.warn("product:{} no stock", productId);
                    return SecKillEnum.NO_STOCK;
                }
            } else {
                //说明没有抢到商品
                log.warn("user:{} blocked ", userId);
                return SecKillEnum.RETRY;
            }

        } catch (InterruptedException e) {
            log.info("{}", e.getMessage());
            throw new RuntimeException(e);
        } finally {
            // 确保只有在当前线程持有锁时才释放锁
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return SecKillEnum.SUCCESS;
    }
}
